import React, { createContext, useContext, useReducer, useState } from "react"
// 导入React核心库和必要的hooks：createContext用于创建上下文，useContext用于使用上下文
// useReducer用于复杂状态管理，useState用于简单状态管理

// Define types
interface Todo {
  id: number // 每个待办事项的唯一标识符
  text: string // 待办事项的文本内容
  completed: boolean // 表示待办事项是否已完成的状态
}

type TodoState = {
  todos: Todo[] // 定义应用状态类型，包含一个Todo对象数组
}

type TodoAction =
  | { type: "ADD_TODO"; payload: string } // 添加待办事项的action，payload是待办事项文本
  | { type: "TOGGLE_TODO"; payload: number } // 切换待办事项完成状态的action，payload是待办事项ID
  | { type: "DELETE_TODO"; payload: number } // 删除待办事项的action，payload是待办事项ID

// Create initial state
const initialState: TodoState = {
  todos: [
    { id: 1, text: "学习 React Context", completed: false }, // 初始待办事项1
    { id: 2, text: "学习 useReducer Hook", completed: false }, // 初始待办事项2
  ],
}

// Create reducer function
const todoReducer = (state: TodoState, action: TodoAction): TodoState => {
  // reducer函数接收当前状态和action，返回新状态
  switch (action.type) {
    case "ADD_TODO":
      const find = state.todos.find((item) => {
        return item.text == action.payload
      })
      if (find) {
        alert("已存在")
        return state
      }

      return {
        ...state, // 保留原状态的其他属性
        todos: [
          ...state.todos, // 保留原有的待办事项
          {
            id: Date.now(), // 使用当前时间戳作为新待办事项的ID
            text: action.payload, // 使用action的payload作为待办事项文本
            completed: false, // 新添加的待办事项默认为未完成状态
          },
        ],
      }

    case "TOGGLE_TODO":
      return {
        ...state, // 保留原状态的其他属性
        todos: state.todos.map(
          (todo) =>
            todo.id === action.payload
              ? { ...todo, completed: !todo.completed } // 如果ID匹配，切换完成状态
              : todo // 否则保持不变
        ),
      }

    case "DELETE_TODO":
      return {
        ...state, // 保留原状态的其他属性
        todos: state.todos.filter((todo) => todo.id !== action.payload), // 过滤掉ID匹配的待办事项
      }

    default:
      return state // 对于未知的action类型，返回原状态
  }
}

// Create context
type TodoContextType = {
  state: TodoState // 上下文中包含的状态
  dispatch: React.Dispatch<TodoAction> // 上下文中包含的dispatch函数，用于发送action
}

const TodoContext = createContext<TodoContextType | undefined>(undefined)
// 创建上下文，初始值为undefined，使用TypeScript泛型确保类型安全

// Create Provider component
const TodoProvider: React.FC<{ children: React.ReactNode }> = ({
  children,
}) => {
  const [state, dispatch] = useReducer(todoReducer, initialState) // 使用 useReducer 创建状态管理
  // useReducer接收reducer函数和初始状态，返回当前状态和dispatch函数

  return (
    <TodoContext.Provider value={{ state, dispatch }}>
      {children} // 渲染子组件，使它们能够访问上下文
    </TodoContext.Provider>
  )
}

// Custom hook for using the context
const useTodoContext = () => {
  const context = useContext(TodoContext) // 使用useContext获取上下文值
  if (!context) {
    throw new Error("useTodoContext must be used within a TodoProvider")
    // 如果上下文不存在（即组件不在Provider内部），抛出错误
  }
  return context // 返回上下文值，包含state和dispatch
}

// TodoList component
const TodoList: React.FC = () => {
  const { state, dispatch } = useTodoContext() // 使用自定义hook获取上下文

  return (
    <ul className="todo-list">
      {state.todos.map(
        (
          todo // 遍历todos数组，为每个待办事项创建列表项
        ) => (
          <li key={todo.id} className={todo.completed ? "completed" : ""}>
            {/* 根据完成状态设置CSS类 */}
            <span
              onClick={() =>
                dispatch({ type: "TOGGLE_TODO", payload: todo.id })
              }
              // 点击文本时，发送TOGGLE_TODO action切换完成状态
            >
              {todo.text} {/* 显示待办事项文本 */}
            </span>
            <button
              onClick={() =>
                dispatch({ type: "DELETE_TODO", payload: todo.id })
              }
              // 点击按钮时，发送DELETE_TODO action删除待办事项
            >
              删除
            </button>
          </li>
        )
      )}
    </ul>
  )
}

// AddTodo component
const AddTodo: React.FC = () => {
  const [text, setText] = useState("") // 使用useState管理输入框的文本状态
  const { dispatch } = useTodoContext() // 从上下文中只获取dispatch函数

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault() // 阻止表单默认提交行为
    if (text.trim()) {
      // 检查输入是否为空（去除空格后）
      dispatch({ type: "ADD_TODO", payload: text }) // 发送ADD_TODO action添加新待办事项
      setText("") // 清空输入框
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      {" "}
      {/* 表单提交时调用handleSubmit函数 */}
      <input
        type="text"
        value={text} // 输入框的值绑定到text状态
        onChange={(e) => setText(e.target.value)} // 输入变化时更新text状态
        placeholder="添加新任务..."
      />
      <button type="submit">添加</button> {/* 提交按钮 */}
    </form>
  )
}

// Main component that uses Context + useReducer
const ContextExample: React.FC = () => {
  return (
    <div className="state-example">
      <h2>Context + useReducer 实现</h2>
      <p>此方案使用 React 内置的 Context API 和 useReducer Hook 实现状态管理</p>

      <TodoProvider>
        {" "}
        {/* 使用TodoProvider包裹子组件，提供上下文 */}
        <div className="todo-container">
          <AddTodo /> {/* 添加待办事项组件 */}
          <TodoList /> {/* 待办事项列表组件 */}
        </div>
      </TodoProvider>

      <div className="explanation">
        <h3>核心概念:</h3>
        <ul>
          <li>
            <strong>Context API</strong>:
            提供一种跨组件共享状态的方法，不必通过组件树逐层传递 props
          </li>
          <li>
            <strong>useReducer</strong>: 适用于复杂状态逻辑管理，使用类似 Redux
            的 action/reducer 模式
          </li>
          <li>
            <strong>Action</strong>: 描述状态变化的对象，有 type 和 payload 属性
          </li>
          <li>
            <strong>Reducer</strong>: 纯函数，根据当前状态和 action 计算新状态
          </li>
        </ul>

        <h3>面试考点:</h3>
        <ul>
          <li>useReducer 与 useState 的区别及使用场景</li>
          <li>
            Context API 的性能考量 (当 Context 值变化时，所有消费该 Context
            的组件都会重新渲染)
          </li>
          <li>如何组织和设计 reducer、actions 和状态结构</li>
          <li>如何避免不必要的重渲染 (如使用 React.memo 或状态拆分)</li>
        </ul>
      </div>
    </div>
  )
}

export default ContextExample // 导出主组件，使其可以在其他文件中导入使用
